/*****************************************************************************
 *  This file is part of the OpenDomo project.
 *  Copyright(C) 2011 OpenDomo Services SL
 *  
 *  Daniel Lerch Hostalot <dlerch@opendomo.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************************/

// ----------------------------------------------------------------------------
// author: Daniel Lerch <dlerch@gmail.com>, http://opendomo.com
// date: January 2007
// description: micropik-ps3x8 driver
//
// CHANGES:
//
// January 2008: add upnpdev_set_* functions and callback method.
// ----------------------------------------------------------------------------


#include <stdio.h>
#include <signal.h>

#include <ps3x8.h>
#include <util.h>
#include <upnpdev.h>
#include <upnplog.h>

#define UPNPDEV_DEVICE_PATH "/var/www/upnp/web-micropik-ps3x8"
#define UPNPDEV_UDN "uuid:Upnp-OpenDomo-micropik-ps3x8-1_0-000E35322D2C"
#define UPNPDEV_SERVICE_ID "urn:upnp-org:serviceId:control1"
#define UPNPDEV_SERVICE_TYPE "urn:schemas-upnp-org:service:control:1"


char *var_names[] = { "output1", "output2" , "output3", "output4",
                      "output5", "output6", "output7", "output8" };

char *var_values[] = { "0", "0", "0", "0", "0", "0", "0", "0" };

unsigned int var_size = 7;

unsigned int i_data = 0; 
unsigned int o_data = 0;

/* device descriptor*/
int dev_desc;


// {{{ upnpdev_set_output1()
int upnpdev_set_output1( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output1")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output1, value: %d\n", output);
  

   // Activar la salida 1 de la placa
#ifndef DUMMY
   PS3X8_SET_IO1(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif 
  
   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output1", UPNPDEV_SERVICE_TYPE, 
               "new_output1", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output2()
int upnpdev_set_output2( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   upnplog_printf(UPNPLOG_INFO, "set_output2()\n");
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output2")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output2, value: %d\n", output);
   
   // Activar la salida 2 de la placa
#ifndef DUMMY
   PS3X8_SET_IO2(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif
   
   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output2", UPNPDEV_SERVICE_TYPE, 
               "new_output2", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output3()
int upnpdev_set_output3( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output3")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output3, value: %d\n", output);
   
   // Activar la salida 3 de la placa
#ifndef DUMMY
   PS3X8_SET_IO3(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif   

   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output3", UPNPDEV_SERVICE_TYPE, 
               "new_output3", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output4()
int upnpdev_set_output4( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output4")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output4, value: %d\n", output);
   
   // Activar la salida 4 de la placa
#ifndef DUMMY
   PS3X8_SET_IO4(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif   

   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output4", UPNPDEV_SERVICE_TYPE, 
               "new_output4", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output5()
int upnpdev_set_output5( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output5")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output5, value: %d\n", output);
   
   // Activar la salida 5 de la placa
#ifndef DUMMY
   PS3X8_SET_IO5(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif 
  
   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output5", UPNPDEV_SERVICE_TYPE, 
               "new_output5", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output6()
int upnpdev_set_output6( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output6")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output6, value: %d\n", output);
   
   // Activar la salida 6 de la placa
#ifndef DUMMY
   PS3X8_SET_IO6(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif   

   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output6", UPNPDEV_SERVICE_TYPE, 
               "new_output6", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output7()
int upnpdev_set_output7( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output7")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output7, value: %d\n", output);
   
   // Activar la salida 7 de la placa
#ifndef DUMMY
   PS3X8_SET_IO7(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif   

   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output7", UPNPDEV_SERVICE_TYPE, 
               "new_output7", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_set_output8()
int upnpdev_set_output8( IN IXML_Document * in, OUT IXML_Document ** out,
      OUT char **error_string )
{
   ( *out ) = NULL;
   ( *error_string ) = NULL;
   char *value = NULL;
   int output = 0; 
   int ret = 0;

   if( !( value = util_get_first_document_item(in, "output8")) ) 
   {
      ( *error_string ) = "Invalid value";
      return UPNP_E_INVALID_PARAM;
   }

   output = atoi(value);
   
   upnplog_printf(UPNPLOG_INFO, "set_output8, value: %d\n", output);
   
   // Activar la salida 8 de la placa
#ifndef DUMMY
   PS3X8_SET_IO8(output, o_data);
   ret = ps3x8_write_digital_data(dev_desc, o_data);
#endif 
  
   if(ret==0) 
   {
      // create a response
      if( UpnpAddToActionResponse( out, "set_output8", UPNPDEV_SERVICE_TYPE, 
               "new_output8", value ) != UPNP_E_SUCCESS ) 
      {
         ( *out ) = NULL;
         ( *error_string ) = "Internal Error";
         return UPNP_E_INTERNAL_ERROR;
      }
      return UPNP_E_SUCCESS;
   } 
   else 
   {
      ( *error_string ) = "Internal Error";
      return UPNP_E_INTERNAL_ERROR;
   }

}
// }}}

// {{{ upnpdev_callback()
int upnpdev_callback(Upnp_EventType event_type, void *event, void *cookie)
{
   switch(event_type) 
   {
     case UPNP_EVENT_SUBSCRIPTION_REQUEST:
      {
         struct Upnp_Subscription_Request *sr = 
            (struct Upnp_Subscription_Request *)event;

         if( (strcmp(sr->UDN, UPNPDEV_UDN) == 0) &&
             (strcmp(sr->ServiceId, UPNPDEV_SERVICE_ID) == 0) )
         {
            UpnpAcceptSubscription(hdl, sr->UDN, sr->ServiceId, 
                  (const char **)var_names, (const char **)var_values, 
                  var_size, sr->Sid);
         }

         break;
      }

      case UPNP_CONTROL_GET_VAR_REQUEST:
      {
         upnplog_printf(UPNPLOG_INFO, "Get Var Request\n"); 

         struct Upnp_State_Var_Request *sv =
            (struct Upnp_State_Var_Request *)event;

         sv->CurrentVal = NULL;
         int getvar_succeeded = 0;
            
         if( (strcmp(sv->DevUDN, UPNPDEV_UDN) == 0) &&
             (strcmp(sv->ServiceID, UPNPDEV_SERVICE_ID) == 0) )
         {


            // {{{ getvar
            char value[32];
            value[0]=0;
            int ret=0;
            if(strcmp(sv->StateVarName, "output1") == 0)
            {
               getvar_succeeded = 1;
               
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO1(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output2") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO2(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output3") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO3(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output4") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO4(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output5") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO5(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output6") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO6(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output7") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO7(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "output8") == 0)
            {
               getvar_succeeded = 1;
               snprintf(value, sizeof(value), "%d", PS3X8_GET_IO8(o_data));
               sv->CurrentVal = ixmlCloneDOMString(value); 
            }
            else if(strcmp(sv->StateVarName, "input1") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO1(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input2") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO2(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input3") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO3(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input4") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO4(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input5") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO5(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input6") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO6(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input7") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO7(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            else if(strcmp(sv->StateVarName, "input8") == 0)
            {
#ifndef DUMMY
               ret = ps3x8_read_digital_data(dev_desc, &i_data);
#endif
               if(ret==0)
               {
                  getvar_succeeded = 1;
                  snprintf(value, sizeof(value), "%d", PS3X8_GET_IO8(i_data));
                  sv->CurrentVal = ixmlCloneDOMString(value); 
               }
            }
            // }}}

            if(!getvar_succeeded)
            {
               upnplog_printf(UPNPLOG_ERROR, 
                     "Error in UPNP_CONTROL_GET_VAR_REQUEST callback\n");

               upnplog_printf(UPNPLOG_ERROR, 
                     "Unknown variable name = %s\n", sv->StateVarName);

               sv->ErrCode = 404;
               strcpy(sv->ErrStr, "Invalid Variable");
            }

         }

         break;
      }
 
      case UPNP_CONTROL_ACTION_REQUEST:
      {
         upnplog_printf(UPNPLOG_INFO, "Action Request\n"); 
         
         struct Upnp_Action_Request *ar = 
            (struct Upnp_Action_Request *)event;

         int action_found = 0;
         int retCode = 0;
         char *error_string = NULL;
            
         
         if( (strcmp(ar->DevUDN, UPNPDEV_UDN) == 0) &&
             (strcmp(ar->ServiceID, UPNPDEV_SERVICE_ID) == 0))
         {

            // {{{ actions
            if(strcmp(ar->ActionName, "set_output1") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output1\n"); 
               retCode = upnpdev_set_output1( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output2") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output2\n"); 
               retCode = upnpdev_set_output2( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output3") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output3\n"); 
               retCode = upnpdev_set_output3( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output4") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output4\n"); 
               retCode = upnpdev_set_output4( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output5") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output5\n"); 
               retCode = upnpdev_set_output5( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output6") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output6\n"); 
               retCode = upnpdev_set_output6( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output7") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output7\n"); 
               retCode = upnpdev_set_output7( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            else if(strcmp( ar->ActionName, "set_output8") == 0 )
            {
               upnplog_printf(UPNPLOG_INFO, "set_output8\n"); 
               retCode = upnpdev_set_output8( 
                     ar->ActionRequest,
                     &ar->ActionResult,
                     &error_string
                     );
               action_found = 1;
            } 
            // }}}
         }


         if(!action_found) 
         {
            upnplog_printf(UPNPLOG_INFO, "Invalid Action\n");
            ar->ActionResult = NULL;
            strcpy(ar->ErrStr, "Invalid Action" );
            ar->ErrCode = 401;
         } 
         else 
         {
            if( retCode == UPNP_E_SUCCESS ) 
            {
               ar->ErrCode = UPNP_E_SUCCESS;
            } 
            else 
            {
               //copy the error string 
               strcpy( ar->ErrStr, error_string );
               switch ( retCode ) 
               {
                  case UPNP_E_INVALID_PARAM:
                     {
                        ar->ErrCode = 402;
                        break;
                     }
                  case UPNP_E_INTERNAL_ERROR:
                  default:
                     {
                        ar->ErrCode = 501;
                        break;
                     }

               }
            }
         }




         break;
      }

      case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
      case UPNP_DISCOVERY_SEARCH_RESULT:
      case UPNP_DISCOVERY_SEARCH_TIMEOUT:
      case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
      case UPNP_CONTROL_ACTION_COMPLETE:
      case UPNP_CONTROL_GET_VAR_COMPLETE:
      case UPNP_EVENT_RECEIVED:
      case UPNP_EVENT_SUBSCRIBE_COMPLETE:
      case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
      case UPNP_EVENT_RENEWAL_COMPLETE:
      case UPNP_EVENT_AUTORENEWAL_FAILED:
      case UPNP_EVENT_SUBSCRIPTION_EXPIRED:

      break;
   }

   return 0;
}
// }}}

int main(int argc, char **argv)
{
   sigset_t sigs_to_catch;
   int sig;

#ifndef DUMMY
   if(argc!=2)
   {
      printf("Usage: %s <dev>\n", argv[0]);
      return 0;
   }

   // serial connection
   if( (dev_desc = ps3x8_connect(argv[1])) <= 0)
   {
      printf("device connection error: %s\n", argv[1]);
      return 0;      
   }
#endif

   // Start UPnP Device
   upnpdev_init(NULL, 0, "device.xml", UPNPDEV_DEVICE_PATH, upnpdev_callback);


   // Waiting signal
   sigemptyset(&sigs_to_catch);
   sigaddset(&sigs_to_catch, SIGINT);
   sigwait(&sigs_to_catch, &sig);

   // Stop
   util_print( "Shutting down on signal %d...\n", sig );
   upnpdev_cleanup();

   // disconnect ps3x8
#ifndef DUMMY
   ps3x8_disconnect(dev_desc);
#endif

   return 0;
}



